/*******************************************************************************
** File Name:    softtimer.c
** note:         softtimer
** Author:       lijw
** Version:      1.0
** Created Data: 2023-04-02
** islijw@163.com
**
** Copyright (c) 2023 lijw
** All rights reserved.
*******************************************************************************/

#include "soft_timer.h"
/*
    do{...}while(0)的作用
    1 代码分块，比仅仅使用{}更直观些，并且如果只用{}，在if-else展开时可能会出错
        如 #define DOSOMETHING() { action1(); action2(); }
        if(NULL == pPointer)
            DOSOMETHING();
        else
            ...
        if(NULL == pPointer)
        {
            action1();
            action2();
        };
        else
            ...
    2 执行一段代码到一半，想跳过剩下的一半的时候，能用break达到这个目的，相当于变形的goto
    3 避免空宏引起的警告
 */
#define TIMER_ASSERT(x)                       \
do{                                           \
    if((x == NULL)&&(x == soft_timer_error))  \
        return soft_timer_error;              \
}while(0)



#define container_of(ptr, type, member) ( \
	(type *)( (char *)(ptr) - (size_t) &((type *)0)->member ))

/* 定时器边界定时周期 */
#define SOFT_TIMER_MAX_INTERVAL   (((soft_timer_ticks_t)0xffffffff - 1)/2)
#define SOFT_TIMER_MIN_INTERVAL   (1)


/* 定时器管理器 */
struct _soft_timer
{
    /* 链表头指针，指向定时器链表头 */
    soft_timer_list_item_t list_head;
    /* 定时器ticks */
    volatile soft_timer_ticks_t ticks;
    int timer_num;
    soft_timer_status_t init_flag;
};

struct _soft_timer soft_timer = {
    .timer_num = 0,
    .ticks = 0,
    .init_flag = soft_timer_error,
};

soft_timer_list_item_t* ptimer_head_item = &(soft_timer.list_head);


static soft_timer_ticks_t soft_timer_get_ticks(void);
static soft_timer_status_t is_item_in_list(soft_timer_list_item_t* item);
static soft_timer_status_t is_list_empty(void);
static soft_timer_status_t remove_item_from_list(soft_timer_list_item_t* item);
static soft_timer_status_t add_item_to_list_head(soft_timer_list_item_t* item);

/* 初始化定时器 */
soft_timer_status_t soft_timer_add(soft_timer_t *ptimer,
                   int times,
                   soft_timer_ticks_t interval,
                   soft_timer_cb_t *cb,
                   void* parm)
{
    TIMER_ASSERT(ptimer);
    TIMER_ASSERT(cb);
    if ((interval < SOFT_TIMER_MIN_INTERVAL) || (interval > SOFT_TIMER_MAX_INTERVAL))
        return soft_timer_error;
    if(soft_timer.init_flag == soft_timer_error)
    {
        ptimer_head_item->next = ptimer_head_item;
        ptimer_head_item->prev = ptimer_head_item;
        soft_timer.init_flag = soft_timer_ok;
    }
    if(is_item_in_list(&(ptimer->item)) == soft_timer_ok)
    {
        return soft_timer_error;
    }
    ptimer->times = times;
    ptimer->last_ticks = soft_timer_get_ticks();
    ptimer->interval = interval;
    ptimer->cb = cb;
    ptimer->parm = parm;
    return add_item_to_list_head(&(ptimer->item));
}
/* 删除定时器 */
soft_timer_status_t soft_timer_delete(soft_timer_t *ptimer)
{
    return remove_item_from_list(&(ptimer->item));
}
/* 修改定时器参数 */
soft_timer_status_t soft_timer_modify(soft_timer_t *ptimer,
                   int times,
                   soft_timer_ticks_t interval,
                   soft_timer_cb_t *cb,
                   void* parm)
{
    TIMER_ASSERT(ptimer);
    TIMER_ASSERT(cb);
    if ((interval < SOFT_TIMER_MIN_INTERVAL) || (interval > SOFT_TIMER_MAX_INTERVAL))
    {
        return soft_timer_error;
    }
    if(is_item_in_list(&(ptimer->item)) == soft_timer_error)
    {
        return soft_timer_error;
    }
    ptimer->times = times;
    ptimer->last_ticks = soft_timer_get_ticks();
    ptimer->interval = interval;
    ptimer->cb = cb;
    ptimer->parm = parm;
    return soft_timer_ok;
}
/* 定时器事件轮询处理 */
void soft_timer_loop(void)
{
    soft_timer_t* ptemp_timer;
    soft_timer_list_item_t *ptemp_item;
    soft_timer_ticks_t current_ticks = soft_timer_get_ticks();
    soft_timer_ticks_t wake_ticks;
    soft_timer_status_t process_cb_flag;
    for (ptemp_item = ptimer_head_item->next; ptemp_item != ptimer_head_item; ptemp_item = ptemp_item->next)
    {
        process_cb_flag = soft_timer_ok;
        ptemp_timer = container_of(ptemp_item,soft_timer_t,item);
        while(process_cb_flag == soft_timer_ok)
        {
            /* ticks溢出 */
            wake_ticks = ptemp_timer->last_ticks + ptemp_timer->interval;
            if(current_ticks < ptemp_timer->last_ticks)
            {
                /* 分别为wake_ticks溢出，和没溢出 */
                if((current_ticks >= wake_ticks) || (wake_ticks > ptemp_timer->last_ticks))
                {
                    process_cb_flag = soft_timer_ok;
                }
                else
                {
                    process_cb_flag = soft_timer_error;
                }
            }else
            {
                if((current_ticks >= wake_ticks) && (wake_ticks > ptemp_timer->last_ticks))
                {
                    process_cb_flag = soft_timer_ok;
                }
                else
                {
                    process_cb_flag = soft_timer_error;
                }
            }
            if(process_cb_flag == soft_timer_ok)
            {
                /* 重点在于更新ptemp_timer->last_ticks之后，如果没有定时器执行次数不够
                    需要再循环判断当前ticks是否满足条件 */
                if(ptemp_timer->times != 0)
                {
                    if(ptemp_timer->times > 0)
                    {
                        ptemp_timer->times--;
                    }
                    ptemp_timer->last_ticks = ptemp_timer->last_ticks + ptemp_timer->interval;
                    //printf("current_ticks = %u, wake_ticks = %u\n",current_ticks,wake_ticks);
                    ptemp_timer->cb(ptemp_timer->parm);
                }
                if(ptemp_timer->times == 0)
                {
                    soft_timer_delete(ptemp_timer);
                    process_cb_flag = soft_timer_error;
                }  
            }
        }
    }
}


/****************************************************/
/****************   定时器链表管理   *****************/
/****************************************************/
/* 判断节点是否在链表中 */
soft_timer_status_t is_item_in_list(soft_timer_list_item_t* item)
{
    soft_timer_list_item_t* temp_item = ptimer_head_item->next;
    while(temp_item != ptimer_head_item)
    {
        if (temp_item == item)
        {
            return soft_timer_ok;
        }
        temp_item = temp_item->next;
    }
    return soft_timer_error;
}

soft_timer_status_t is_list_empty(void)
{
    if(ptimer_head_item->next = ptimer_head_item)
        return soft_timer_ok;
    else
        return soft_timer_error;
}
/* 从链表移除节点 */
soft_timer_status_t remove_item_from_list(soft_timer_list_item_t* item)
{
    if(is_item_in_list(item) == soft_timer_ok)
    {
        item->prev->next = item->next;
        item->next->prev = item->prev;
        item->next = NULL;
        item->prev = NULL;
        soft_timer.timer_num--;
        return soft_timer_ok;
    }
    return soft_timer_error;
}

/* 添加节点到链表头部 */
soft_timer_status_t add_item_to_list_head(soft_timer_list_item_t* item)
{
    if(is_item_in_list(item) == soft_timer_error)
    {
        item->prev = ptimer_head_item;
        item->next = ptimer_head_item->next;
        item->next->prev = item;
        ptimer_head_item->next = item;
        soft_timer.timer_num++;
        return soft_timer_ok;
    }
    return soft_timer_error;
}

/****************************************************/
/*******************  ticks 管理 ********************/
/****************************************************/
/* 获取系统ticks总数 */
soft_timer_ticks_t soft_timer_get_ticks(void)
{
    return soft_timer.ticks;
}

/* 定时器ticks自增 */
void soft_timer_inc_ticks(void)
{
    soft_timer.ticks++;
}
/****************************************************/
/*******************  delay 管理 ********************/
/****************************************************/


void soft_timer_delay_ticks(soft_timer_ticks_t delay_ticks)
{
    soft_timer_ticks_t current_ticks;
    soft_timer_ticks_t last_ticks = soft_timer_get_ticks();
    soft_timer_ticks_t wake_ticks = last_ticks + delay_ticks;
    while(1)
    {
        current_ticks = soft_timer_get_ticks();
        //溢出
        if(current_ticks < last_ticks)
        {
            if((current_ticks >= wake_ticks) || (wake_ticks > last_ticks))
            {
                break;
            }
        }else
        {
            if((current_ticks >= wake_ticks) && (wake_ticks > last_ticks))
            {
                break;
            }
        }

    }
}


